home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 52 / Amiga Format AFCD52 (Issue 136, May 2000).iso / -screenplay- / shareware / warpquake / warpquakesrc / r_draw.c < prev    next >
C/C++ Source or Header  |  2000-02-29  |  21KB  |  909 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20.  
  21. // r_draw.c
  22.  
  23. #include "quakedef.h"
  24. #include "r_local.h"
  25. #include "d_local.h"    // FIXME: shouldn't need to include this
  26.  
  27. #define MAXLEFTCLIPEDGES        100
  28.  
  29. // !!! if these are changed, they must be changed in asm_draw.h too !!!
  30. #define FULLY_CLIPPED_CACHED    0x80000000
  31. #define FRAMECOUNT_MASK            0x7FFFFFFF
  32.  
  33. unsigned int    cacheoffset;
  34.  
  35. int            c_faceclip;                    // number of faces clipped
  36.  
  37. zpointdesc_t    r_zpointdesc;
  38.  
  39. polydesc_t        r_polydesc;
  40.  
  41.  
  42.  
  43. clipplane_t    *entity_clipplanes;
  44. clipplane_t    view_clipplanes[4];
  45. clipplane_t    world_clipplanes[16];
  46.  
  47. medge_t            *r_pedge;
  48.  
  49. qboolean        r_leftclipped, r_rightclipped;
  50. static qboolean    makeleftedge, makerightedge;
  51. qboolean        r_nearzionly;
  52.  
  53. int        sintable[SIN_BUFFER_SIZE];
  54. int        intsintable[SIN_BUFFER_SIZE];
  55.  
  56. mvertex_t    r_leftenter, r_leftexit;
  57. mvertex_t    r_rightenter, r_rightexit;
  58.  
  59. typedef struct
  60. {
  61.     float    u,v;
  62.     int        ceilv;
  63. } evert_t;
  64.  
  65. int                r_emitted;
  66. float            r_nearzi;
  67. float            r_u1, r_v1, r_lzi1;
  68. int                r_ceilv1;
  69.  
  70. qboolean    r_lastvertvalid;
  71.  
  72.  
  73. #if    !id386
  74.  
  75. /*
  76. ================
  77. R_EmitEdge
  78. ================
  79. */
  80. void R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1)
  81. {
  82.     edge_t    *edge, *pcheck;
  83.     int        u_check;
  84.     float    u, u_step;
  85.     vec3_t    local, transformed;
  86.     float    *world;
  87.     int        v, v2, ceilv0;
  88.     float    scale, lzi0, u0, v0;
  89.     int        side;
  90.  
  91.     if (r_lastvertvalid)
  92.     {
  93.         u0 = r_u1;
  94.         v0 = r_v1;
  95.         lzi0 = r_lzi1;
  96.         ceilv0 = r_ceilv1;
  97.     }
  98.     else
  99.     {
  100.         world = &pv0->position[0];
  101.     
  102.     // transform and project
  103.         VectorSubtract (world, modelorg, local);
  104.         TransformVector (local, transformed);
  105.     
  106.         if (transformed[2] < NEAR_CLIP)
  107.             transformed[2] = NEAR_CLIP;
  108.     
  109.         lzi0 = 1.0 / transformed[2];
  110.     
  111.     // FIXME: build x/yscale into transform?
  112.         scale = xscale * lzi0;
  113.         u0 = (xcenter + scale*transformed[0]);
  114.         if (u0 < r_refdef.fvrectx_adj)
  115.             u0 = r_refdef.fvrectx_adj;
  116.         if (u0 > r_refdef.fvrectright_adj)
  117.             u0 = r_refdef.fvrectright_adj;
  118.     
  119.         scale = yscale * lzi0;
  120.         v0 = (ycenter - scale*transformed[1]);
  121.         if (v0 < r_refdef.fvrecty_adj)
  122.             v0 = r_refdef.fvrecty_adj;
  123.         if (v0 > r_refdef.fvrectbottom_adj)
  124.             v0 = r_refdef.fvrectbottom_adj;
  125.     
  126.         ceilv0 = (int) ceil(v0);
  127.     }
  128.  
  129.     world = &pv1->position[0];
  130.  
  131. // transform and project
  132.     VectorSubtract (world, modelorg, local);
  133.     TransformVector (local, transformed);
  134.  
  135.     if (transformed[2] < NEAR_CLIP)
  136.         transformed[2] = NEAR_CLIP;
  137.  
  138.     r_lzi1 = 1.0 / transformed[2];
  139.  
  140.     scale = xscale * r_lzi1;
  141.     r_u1 = (xcenter + scale*transformed[0]);
  142.     if (r_u1 < r_refdef.fvrectx_adj)
  143.         r_u1 = r_refdef.fvrectx_adj;
  144.     if (r_u1 > r_refdef.fvrectright_adj)
  145.         r_u1 = r_refdef.fvrectright_adj;
  146.  
  147.     scale = yscale * r_lzi1;
  148.     r_v1 = (ycenter - scale*transformed[1]);
  149.     if (r_v1 < r_refdef.fvrecty_adj)
  150.         r_v1 = r_refdef.fvrecty_adj;
  151.     if (r_v1 > r_refdef.fvrectbottom_adj)
  152.         r_v1 = r_refdef.fvrectbottom_adj;
  153.  
  154.     if (r_lzi1 > lzi0)
  155.         lzi0 = r_lzi1;
  156.  
  157.     if (lzi0 > r_nearzi)    // for mipmap finding
  158.         r_nearzi = lzi0;
  159.  
  160. // for right edges, all we want is the effect on 1/z
  161.     if (r_nearzionly)
  162.         return;
  163.  
  164.     r_emitted = 1;
  165.  
  166.     r_ceilv1 = (int) ceil(r_v1);
  167.  
  168.  
  169. // create the edge
  170.     if (ceilv0 == r_ceilv1)
  171.     {
  172.     // we cache unclipped horizontal edges as fully clipped
  173.         if (cacheoffset != 0x7FFFFFFF)
  174.         {
  175.             cacheoffset = FULLY_CLIPPED_CACHED |
  176.                     (r_framecount & FRAMECOUNT_MASK);
  177.         }
  178.  
  179.         return;        // horizontal edge
  180.     }
  181.  
  182.     side = ceilv0 > r_ceilv1;
  183.  
  184.     edge = edge_p++;
  185.  
  186.     edge->owner = r_pedge;
  187.  
  188.     edge->nearzi = lzi0;
  189.  
  190.     if (side == 0)
  191.     {
  192.     // trailing edge (go from p1 to p2)
  193.         v = ceilv0;
  194.         v2 = r_ceilv1 - 1;
  195.  
  196.         edge->surfs[0] = surface_p - surfaces;
  197.         edge->surfs[1] = 0;
  198.  
  199.         u_step = ((r_u1 - u0) / (r_v1 - v0));
  200.         u = u0 + ((float)v - v0) * u_step;
  201.     }
  202.     else
  203.     {
  204.     // leading edge (go from p2 to p1)
  205.         v2 = ceilv0 - 1;
  206.         v = r_ceilv1;
  207.  
  208.         edge->surfs[0] = 0;
  209.         edge->surfs[1] = surface_p - surfaces;
  210.  
  211.         u_step = ((u0 - r_u1) / (v0 - r_v1));
  212.         u = r_u1 + ((float)v - r_v1) * u_step;
  213.     }
  214.  
  215.     edge->u_step = u_step*0x100000;
  216.     edge->u = u*0x100000 + 0xFFFFF;
  217.  
  218. // we need to do this to avoid stepping off the edges if a very nearly
  219. // horizontal edge is less than epsilon above a scan, and numeric error causes
  220. // it to incorrectly extend to the scan, and the extension of the line goes off
  221. // the edge of the screen
  222. // FIXME: is this actually needed?
  223.     if (edge->u < r_refdef.vrect_x_adj_shift20)
  224.         edge->u = r_refdef.vrect_x_adj_shift20;
  225.     if (edge->u > r_refdef.vrectright_adj_shift20)
  226.         edge->u = r_refdef.vrectright_adj_shift20;
  227.  
  228. //
  229. // sort the edge in normally
  230. //
  231.     u_check = edge->u;
  232.     if (edge->surfs[0])
  233.         u_check++;    // sort trailers after leaders
  234.  
  235.     if (!newedges[v] || newedges[v]->u >= u_check)
  236.     {
  237.         edge->next = newedges[v];
  238.         newedges[v] = edge;
  239.     }
  240.     else
  241.     {
  242.         pcheck = newedges[v];
  243.         while (pcheck->next && pcheck->next->u < u_check)
  244.             pcheck = pcheck->next;
  245.         edge->next = pcheck->next;
  246.         pcheck->next = edge;
  247.     }
  248.  
  249.     edge->nextremove = removeedges[v2];
  250.     removeedges[v2] = edge;
  251. }
  252.  
  253.  
  254. /*
  255. ================
  256. R_ClipEdge
  257. ================
  258. */
  259. void R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip)
  260. {
  261.     float        d0, d1, f;
  262.     mvertex_t    clipvert;
  263.  
  264.     if (clip)
  265.     {
  266.         do
  267.         {
  268.             d0 = DotProduct (pv0->position, clip->normal) - clip->dist;
  269.             d1 = DotProduct (pv1->position, clip->normal) - clip->dist;
  270.  
  271.             if (d0 >= 0)
  272.             {
  273.             // point 0 is unclipped
  274.                 if (d1 >= 0)
  275.                 {
  276.                 // both points are unclipped
  277.                     continue;
  278.                 }
  279.  
  280.             // only point 1 is clipped
  281.  
  282.             // we don't cache clipped edges
  283.                 cacheoffset = 0x7FFFFFFF;
  284.  
  285.                 f = d0 / (d0 - d1);
  286.                 clipvert.position[0] = pv0->position[0] +
  287.                         f * (pv1->position[0] - pv0->position[0]);
  288.                 clipvert.position[1] = pv0->position[1] +
  289.                         f * (pv1->position[1] - pv0->position[1]);
  290.                 clipvert.position[2] = pv0->position[2] +
  291.                         f * (pv1->position[2] - pv0->position[2]);
  292.  
  293.                 if (clip->leftedge)
  294.                 {
  295.                     r_leftclipped = true;
  296.                     r_leftexit = clipvert;
  297.                 }
  298.                 else if (clip->rightedge)
  299.                 {
  300.                     r_rightclipped = true;
  301.                     r_rightexit = clipvert;
  302.                 }
  303.  
  304.                 R_ClipEdge (pv0, &clipvert, clip->next);
  305.                 return;
  306.             }
  307.             else
  308.             {
  309.             // point 0 is clipped
  310.                 if (d1 < 0)
  311.                 {
  312.                 // both points are clipped
  313.                 // we do cache fully clipped edges
  314.                     if (!r_leftclipped)
  315.                         cacheoffset = FULLY_CLIPPED_CACHED |
  316.                                 (r_framecount & FRAMECOUNT_MASK);
  317.                     return;
  318.                 }
  319.  
  320.             // only point 0 is clipped
  321.                 r_lastvertvalid = false;
  322.  
  323.             // we don't cache partially clipped edges
  324.                 cacheoffset = 0x7FFFFFFF;
  325.  
  326.                 f = d0 / (d0 - d1);
  327.                 clipvert.position[0] = pv0->position[0] +
  328.                         f * (pv1->position[0] - pv0->position[0]);
  329.                 clipvert.position[1] = pv0->position[1] +
  330.                         f * (pv1->position[1] - pv0->position[1]);
  331.                 clipvert.position[2] = pv0->position[2] +
  332.                         f * (pv1->position[2] - pv0->position[2]);
  333.  
  334.                 if (clip->leftedge)
  335.                 {
  336.                     r_leftclipped = true;
  337.                     r_leftenter = clipvert;
  338.                 }
  339.                 else if (clip->rightedge)
  340.                 {
  341.                     r_rightclipped = true;
  342.                     r_rightenter = clipvert;
  343.                 }
  344.  
  345.                 R_ClipEdge (&clipvert, pv1, clip->next);
  346.                 return;
  347.             }
  348.         } while ((clip = clip->next) != NULL);
  349.     }
  350.  
  351. // add the edge
  352.     R_EmitEdge (pv0, pv1);
  353. }
  354.  
  355. #endif    // !id386
  356.  
  357.  
  358. /*
  359. ================
  360. R_EmitCachedEdge
  361. ================
  362. */
  363. void R_EmitCachedEdge (void)
  364. {
  365.     edge_t        *pedge_t;
  366.  
  367.     pedge_t = (edge_t *)((unsigned long)r_edges + r_pedge->cachededgeoffset);
  368.  
  369.     if (!pedge_t->surfs[0])
  370.         pedge_t->surfs[0] = surface_p - surfaces;
  371.     else
  372.         pedge_t->surfs[1] = surface_p - surfaces;
  373.  
  374.     if (pedge_t->nearzi > r_nearzi)    // for mipmap finding
  375.         r_nearzi = pedge_t->nearzi;
  376.  
  377.     r_emitted = 1;
  378. }
  379.  
  380.  
  381. /*
  382. ================
  383. R_RenderFace
  384. ================
  385. */
  386. void R_RenderFace (msurface_t *fa, int clipflags)
  387. {
  388.     int            i, lindex;
  389.     unsigned    mask;
  390.     mplane_t    *pplane;
  391.     float        distinv;
  392.     vec3_t        p_normal;
  393.     medge_t        *pedges, tedge;
  394.     clipplane_t    *pclip;
  395.  
  396. // skip out if no more surfs
  397.     if ((surface_p) >= surf_max)
  398.     {
  399.         r_outofsurfaces++;
  400.         return;
  401.     }
  402.  
  403. // ditto if not enough edges left, or switch to auxedges if possible
  404.     if ((edge_p + fa->numedges + 4) >= edge_max)
  405.     {
  406.         r_outofedges += fa->numedges;
  407.         return;
  408.     }
  409.  
  410.     c_faceclip++;
  411.  
  412. // set up clip planes
  413.     pclip = NULL;
  414.  
  415.     for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
  416.     {
  417.         if (clipflags & mask)
  418.         {
  419.             view_clipplanes[i].next = pclip;
  420.             pclip = &view_clipplanes[i];
  421.         }
  422.     }
  423.  
  424. // push the edges through
  425.     r_emitted = 0;
  426.     r_nearzi = 0;
  427.     r_nearzionly = false;
  428.     makeleftedge = makerightedge = false;
  429.     pedges = currententity->model->edges;
  430.     r_lastvertvalid = false;
  431.  
  432.     for (i=0 ; i<fa->numedges ; i++)
  433.     {
  434.         lindex = currententity->model->surfedges[fa->firstedge + i];
  435.  
  436.         if (lindex > 0)
  437.         {
  438.             r_pedge = &pedges[lindex];
  439.  
  440.         // if the edge is cached, we can just reuse the edge
  441.             if (!insubmodel)
  442.             {
  443.                 if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
  444.                 {
  445.                     if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
  446.                         r_framecount)
  447.                     {
  448.                         r_lastvertvalid = false;
  449.                         continue;
  450.                     }
  451.                 }
  452.                 else
  453.                 {
  454.                     if ((((unsigned long)edge_p - (unsigned long)r_edges) >
  455.                          r_pedge->cachededgeoffset) &&
  456.                         (((edge_t *)((unsigned long)r_edges +
  457.                          r_pedge->cachededgeoffset))->owner == r_pedge))
  458.                     {
  459.                         R_EmitCachedEdge ();
  460.                         r_lastvertvalid = false;
  461.                         continue;
  462.                     }
  463.                 }
  464.             }
  465.  
  466.         // assume it's cacheable
  467.             cacheoffset = (byte *)edge_p - (byte *)r_edges;
  468.             r_leftclipped = r_rightclipped = false;
  469.             R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[0]],
  470.                         &r_pcurrentvertbase[r_pedge->v[1]],
  471.                         pclip);
  472.             r_pedge->cachededgeoffset = cacheoffset;
  473.  
  474.             if (r_leftclipped)
  475.                 makeleftedge = true;
  476.             if (r_rightclipped)
  477.                 makerightedge = true;
  478.             r_lastvertvalid = true;
  479.         }
  480.         else
  481.         {
  482.             lindex = -lindex;
  483.             r_pedge = &pedges[lindex];
  484.         // if the edge is cached, we can just reuse the edge
  485.             if (!insubmodel)
  486.             {
  487.                 if (r_pedge->cachededgeoffset & FULLY_CLIPPED_CACHED)
  488.                 {
  489.                     if ((r_pedge->cachededgeoffset & FRAMECOUNT_MASK) ==
  490.                         r_framecount)
  491.                     {
  492.                         r_lastvertvalid = false;
  493.                         continue;
  494.                     }
  495.                 }
  496.                 else
  497.                 {
  498.                 // it's cached if the cached edge is valid and is owned
  499.                 // by this medge_t
  500.                     if ((((unsigned long)edge_p - (unsigned long)r_edges) >
  501.                          r_pedge->cachededgeoffset) &&
  502.                         (((edge_t *)((unsigned long)r_edges +
  503.                          r_pedge->cachededgeoffset))->owner == r_pedge))
  504.                     {
  505.                         R_EmitCachedEdge ();
  506.                         r_lastvertvalid = false;
  507.                         continue;
  508.                     }
  509.                 }
  510.             }
  511.  
  512.         // assume it's cacheable
  513.             cacheoffset = (byte *)edge_p - (byte *)r_edges;
  514.             r_leftclipped = r_rightclipped = false;
  515.             R_ClipEdge (&r_pcurrentvertbase[r_pedge->v[1]],
  516.                         &r_pcurrentvertbase[r_pedge->v[0]],
  517.                         pclip);
  518.             r_pedge->cachededgeoffset = cacheoffset;
  519.  
  520.             if (r_leftclipped)
  521.                 makeleftedge = true;
  522.             if (r_rightclipped)
  523.                 makerightedge = true;
  524.             r_lastvertvalid = true;
  525.         }
  526.     }
  527.  
  528. // if there was a clip off the left edge, add that edge too
  529. // FIXME: faster to do in screen space?
  530. // FIXME: share clipped edges?
  531.     if (makeleftedge)
  532.     {
  533.         r_pedge = &tedge;
  534.         r_lastvertvalid = false;
  535.         R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
  536.     }
  537.  
  538. // if there was a clip off the right edge, get the right r_nearzi
  539.     if (makerightedge)
  540.     {
  541.         r_pedge = &tedge;
  542.         r_lastvertvalid = false;
  543.         r_nearzionly = true;
  544.         R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
  545.     }
  546.  
  547. // if no edges made it out, return without posting the surface
  548.     if (!r_emitted)
  549.         return;
  550.  
  551.     r_polycount++;
  552.  
  553.     surface_p->data = (void *)fa;
  554.     surface_p->nearzi = r_nearzi;
  555.     surface_p->flags = fa->flags;
  556.     surface_p->insubmodel = insubmodel;
  557.     surface_p->spanstate = 0;
  558.     surface_p->entity = currententity;
  559.     surface_p->key = r_currentkey++;
  560.     surface_p->spans = NULL;
  561.  
  562.     pplane = fa->plane;
  563. // FIXME: cache this?
  564.     TransformVector (pplane->normal, p_normal);
  565. // FIXME: cache this?
  566.     distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
  567.  
  568.     surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
  569.     surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
  570.     surface_p->d_ziorigin = p_normal[2] * distinv -
  571.             xcenter * surface_p->d_zistepu -
  572.             ycenter * surface_p->d_zistepv;
  573.  
  574. //JDC    VectorCopy (r_worldmodelorg, surface_p->modelorg);
  575.     surface_p++;
  576. }
  577.  
  578.  
  579. /*
  580. ================
  581. R_RenderBmodelFace
  582. ================
  583. */
  584. void R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf)
  585. {
  586.     int            i;
  587.     unsigned    mask;
  588.     mplane_t    *pplane;
  589.     float        distinv;
  590.     vec3_t        p_normal;
  591.     medge_t        tedge;
  592.     clipplane_t    *pclip;
  593.  
  594. // skip out if no more surfs
  595.     if (surface_p >= surf_max)
  596.     {
  597.         r_outofsurfaces++;
  598.         return;
  599.     }
  600.  
  601. // ditto if not enough edges left, or switch to auxedges if possible
  602.     if ((edge_p + psurf->numedges + 4) >= edge_max)
  603.     {
  604.         r_outofedges += psurf->numedges;
  605.         return;
  606.     }
  607.  
  608.     c_faceclip++;
  609.  
  610. // this is a dummy to give the caching mechanism someplace to write to
  611.     r_pedge = &tedge;
  612.  
  613. // set up clip planes
  614.     pclip = NULL;
  615.  
  616.     for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
  617.     {
  618.         if (r_clipflags & mask)
  619.         {
  620.             view_clipplanes[i].next = pclip;
  621.             pclip = &view_clipplanes[i];
  622.         }
  623.     }
  624.  
  625. // push the edges through
  626.     r_emitted = 0;
  627.     r_nearzi = 0;
  628.     r_nearzionly = false;
  629.     makeleftedge = makerightedge = false;
  630. // FIXME: keep clipped bmodel edges in clockwise order so last vertex caching
  631. // can be used?
  632.     r_lastvertvalid = false;
  633.  
  634.     for ( ; pedges ; pedges = pedges->pnext)
  635.     {
  636.         r_leftclipped = r_rightclipped = false;
  637.         R_ClipEdge (pedges->v[0], pedges->v[1], pclip);
  638.  
  639.         if (r_leftclipped)
  640.             makeleftedge = true;
  641.         if (r_rightclipped)
  642.             makerightedge = true;
  643.     }
  644.  
  645. // if there was a clip off the left edge, add that edge too
  646. // FIXME: faster to do in screen space?
  647. // FIXME: share clipped edges?
  648.     if (makeleftedge)
  649.     {
  650.         r_pedge = &tedge;
  651.         R_ClipEdge (&r_leftexit, &r_leftenter, pclip->next);
  652.     }
  653.  
  654. // if there was a clip off the right edge, get the right r_nearzi
  655.     if (makerightedge)
  656.     {
  657.         r_pedge = &tedge;
  658.         r_nearzionly = true;
  659.         R_ClipEdge (&r_rightexit, &r_rightenter, view_clipplanes[1].next);
  660.     }
  661.  
  662. // if no edges made it out, return without posting the surface
  663.     if (!r_emitted)
  664.         return;
  665.  
  666.     r_polycount++;
  667.  
  668.     surface_p->data = (void *)psurf;
  669.     surface_p->nearzi = r_nearzi;
  670.     surface_p->flags = psurf->flags;
  671.     surface_p->insubmodel = true;
  672.     surface_p->spanstate = 0;
  673.     surface_p->entity = currententity;
  674.     surface_p->key = r_currentbkey;
  675.     surface_p->spans = NULL;
  676.  
  677.     pplane = psurf->plane;
  678. // FIXME: cache this?
  679.     TransformVector (pplane->normal, p_normal);
  680. // FIXME: cache this?
  681.     distinv = 1.0 / (pplane->dist - DotProduct (modelorg, pplane->normal));
  682.  
  683.     surface_p->d_zistepu = p_normal[0] * xscaleinv * distinv;
  684.     surface_p->d_zistepv = -p_normal[1] * yscaleinv * distinv;
  685.     surface_p->d_ziorigin = p_normal[2] * distinv -
  686.             xcenter * surface_p->d_zistepu -
  687.             ycenter * surface_p->d_zistepv;
  688.  
  689. //JDC    VectorCopy (r_worldmodelorg, surface_p->modelorg);
  690.     surface_p++;
  691. }
  692.  
  693.  
  694. /*
  695. ================
  696. R_RenderPoly
  697. ================
  698. */
  699. void R_RenderPoly (msurface_t *fa, int clipflags)
  700. {
  701.     int            i, lindex, lnumverts, s_axis, t_axis;
  702.     float        dist, lastdist, lzi, scale, u, v, frac;
  703.     unsigned    mask;
  704.     vec3_t        local, transformed;
  705.     clipplane_t    *pclip;
  706.     medge_t        *pedges;
  707.     mplane_t    *pplane;
  708.     mvertex_t    verts[2][100];    //FIXME: do real number
  709.     polyvert_t    pverts[100];    //FIXME: do real number, safely
  710.     int            vertpage, newverts, newpage, lastvert;
  711.     qboolean    visible;
  712.  
  713. // FIXME: clean this up and make it faster
  714. // FIXME: guard against running out of vertices
  715.  
  716.     s_axis = t_axis = 0;    // keep compiler happy
  717.  
  718. // set up clip planes
  719.     pclip = NULL;
  720.  
  721.     for (i=3, mask = 0x08 ; i>=0 ; i--, mask >>= 1)
  722.     {
  723.         if (clipflags & mask)
  724.         {
  725.             view_clipplanes[i].next = pclip;
  726.             pclip = &view_clipplanes[i];
  727.         }
  728.     }
  729.  
  730. // reconstruct the polygon
  731. // FIXME: these should be precalculated and loaded off disk
  732.     pedges = currententity->model->edges;
  733.     lnumverts = fa->numedges;
  734.     vertpage = 0;
  735.  
  736.     for (i=0 ; i<lnumverts ; i++)
  737.     {
  738.         lindex = currententity->model->surfedges[fa->firstedge + i];
  739.  
  740.         if (lindex > 0)
  741.         {
  742.             r_pedge = &pedges[lindex];
  743.             verts[0][i] = r_pcurrentvertbase[r_pedge->v[0]];
  744.         }
  745.         else
  746.         {
  747.             r_pedge = &pedges[-lindex];
  748.             verts[0][i] = r_pcurrentvertbase[r_pedge->v[1]];
  749.         }
  750.     }
  751.  
  752. // clip the polygon, done if not visible
  753.     while (pclip)
  754.     {
  755.         lastvert = lnumverts - 1;
  756.         lastdist = DotProduct (verts[vertpage][lastvert].position,
  757.                                pclip->normal) - pclip->dist;
  758.  
  759.         visible = false;
  760.         newverts = 0;
  761.         newpage = vertpage ^ 1;
  762.  
  763.         for (i=0 ; i<lnumverts ; i++)
  764.         {
  765.             dist = DotProduct (verts[vertpage][i].position, pclip->normal) -
  766.                     pclip->dist;
  767.  
  768.             if ((lastdist > 0) != (dist > 0))
  769.             {
  770.                 frac = dist / (dist - lastdist);
  771.                 verts[newpage][newverts].position[0] =
  772.                         verts[vertpage][i].position[0] +
  773.                         ((verts[vertpage][lastvert].position[0] -
  774.                           verts[vertpage][i].position[0]) * frac);
  775.                 verts[newpage][newverts].position[1] =
  776.                         verts[vertpage][i].position[1] +
  777.                         ((verts[vertpage][lastvert].position[1] -
  778.                           verts[vertpage][i].position[1]) * frac);
  779.                 verts[newpage][newverts].position[2] =
  780.                         verts[vertpage][i].position[2] +
  781.                         ((verts[vertpage][lastvert].position[2] -
  782.                           verts[vertpage][i].position[2]) * frac);
  783.                 newverts++;
  784.             }
  785.  
  786.             if (dist >= 0)
  787.             {
  788.                 verts[newpage][newverts] = verts[vertpage][i];
  789.                 newverts++;
  790.                 visible = true;
  791.             }
  792.  
  793.             lastvert = i;
  794.             lastdist = dist;
  795.         }
  796.  
  797.         if (!visible || (newverts < 3))
  798.             return;
  799.  
  800.         lnumverts = newverts;
  801.         vertpage ^= 1;
  802.         pclip = pclip->next;
  803.     }
  804.  
  805. // transform and project, remembering the z values at the vertices and
  806. // r_nearzi, and extract the s and t coordinates at the vertices
  807.     pplane = fa->plane;
  808.     switch (pplane->type)
  809.     {
  810.     case PLANE_X:
  811.     case PLANE_ANYX:
  812.         s_axis = 1;
  813.         t_axis = 2;
  814.         break;
  815.     case PLANE_Y:
  816.     case PLANE_ANYY:
  817.         s_axis = 0;
  818.         t_axis = 2;
  819.         break;
  820.     case PLANE_Z:
  821.     case PLANE_ANYZ:
  822.         s_axis = 0;
  823.         t_axis = 1;
  824.         break;
  825.     }
  826.  
  827.     r_nearzi = 0;
  828.  
  829.     for (i=0 ; i<lnumverts ; i++)
  830.     {
  831.     // transform and project
  832.         VectorSubtract (verts[vertpage][i].position, modelorg, local);
  833.         TransformVector (local, transformed);
  834.  
  835.         if (transformed[2] < NEAR_CLIP)
  836.             transformed[2] = NEAR_CLIP;
  837.  
  838.         lzi = 1.0 / transformed[2];
  839.  
  840.         if (lzi > r_nearzi)    // for mipmap finding
  841.             r_nearzi = lzi;
  842.  
  843.     // FIXME: build x/yscale into transform?
  844.         scale = xscale * lzi;
  845.         u = (xcenter + scale*transformed[0]);
  846.         if (u < r_refdef.fvrectx_adj)
  847.             u = r_refdef.fvrectx_adj;
  848.         if (u > r_refdef.fvrectright_adj)
  849.             u = r_refdef.fvrectright_adj;
  850.  
  851.         scale = yscale * lzi;
  852.         v = (ycenter - scale*transformed[1]);
  853.         if (v < r_refdef.fvrecty_adj)
  854.             v = r_refdef.fvrecty_adj;
  855.         if (v > r_refdef.fvrectbottom_adj)
  856.             v = r_refdef.fvrectbottom_adj;
  857.  
  858.         pverts[i].u = u;
  859.         pverts[i].v = v;
  860.         pverts[i].zi = lzi;
  861.         pverts[i].s = verts[vertpage][i].position[s_axis];
  862.         pverts[i].t = verts[vertpage][i].position[t_axis];
  863.     }
  864.  
  865. // build the polygon descriptor, including fa, r_nearzi, and u, v, s, t, and z
  866. // for each vertex
  867.     r_polydesc.numverts = lnumverts;
  868.     r_polydesc.nearzi = r_nearzi;
  869.     r_polydesc.pcurrentface = fa;
  870.     r_polydesc.pverts = pverts;
  871.  
  872. // draw the polygon
  873.     D_DrawPoly ();
  874. }
  875.  
  876.  
  877. /*
  878. ================
  879. R_ZDrawSubmodelPolys
  880. ================
  881. */
  882. void R_ZDrawSubmodelPolys (model_t *pmodel)
  883. {
  884.     int            i, numsurfaces;
  885.     msurface_t    *psurf;
  886.     float        dot;
  887.     mplane_t    *pplane;
  888.  
  889.     psurf = &pmodel->surfaces[pmodel->firstmodelsurface];
  890.     numsurfaces = pmodel->nummodelsurfaces;
  891.  
  892.     for (i=0 ; i<numsurfaces ; i++, psurf++)
  893.     {
  894.     // find which side of the node we are on
  895.         pplane = psurf->plane;
  896.  
  897.         dot = DotProduct (modelorg, pplane->normal) - pplane->dist;
  898.  
  899.     // draw the polygon
  900.         if (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||
  901.             (!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))
  902.         {
  903.         // FIXME: use bounding-box-based frustum clipping info?
  904.             R_RenderPoly (psurf, 15);
  905.         }
  906.     }
  907. }
  908.  
  909.